#ifndef COROUTINE_SCHEDULER_H
#define COROUTINE_SCHEDULER_H

#include "Fiber.hpp"
#include "../base/BaseLog.hpp"

#include <atomic>
#include <cstddef>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <sys/types.h>
#include <thread>
#include <utility>

namespace DBServer {
namespace coroutine {
    
class Scheduler : public std::enable_shared_from_this<Scheduler> {
public:
    using ptr = std::shared_ptr<Scheduler>;

    /// @brief 创建一个调度器
    /// @param threads 线程池的数量 
    /// @param caller 是否在当前线程调度
    /// @param name 线程名称
    Scheduler(std::size_t threads = 1, bool caller = true, const std::string &name = "") noexcept;

    /// @brief 析构函数
    virtual ~Scheduler() noexcept;

    /// @brief 获取线程的名称
    const std::string& get_name() const { return name; }

    /// @brief 获取当前协程调度器
    static Scheduler* GetThis();

    /// @brief 获取当前协程调度器的主协程
    static Fiber* GetMainFiber();

    /// @brief 启动协程调度器
    void start();

    /// @brief 停止形成调度器
    void stop();

    /// @brief 调度协程
    /// @tparam FiberOrCb 协程或回调函数
    /// @param fc 任务
    /// @param thread 指定执行协程id，-1标识任意线程
    template<class FiberOrCb>
    void schedule(FiberOrCb fc, int thread = -1) {
        bool tick = false;
        {
            std::unique_lock<std::mutex> lock(mtx);
            tick = schedule_no_lock(fc, thread);
        }
        if (tick)
        {
            tickle();
        }
    }

    /// @brief 批量处理任务
    template<class InputItertor>
    void schedule(InputItertor begin, InputItertor end) {
        bool tick = false;
        {
            std::unique_lock<std::mutex> lock(mtx);
            try
            {
                while (begin != end)
                {
                    tick |= schedule_no_lock(std::move(*begin), -1);
                    ++begin;
                }
            }
            catch (const std::exception& e) 
            {
                error("what() : %s\n", e.what());
                throw;
            }
        }
        if (tick)
        {
            tickle();
        }
    }

    /// @brief 
    /// @param thread 
    void switch_to(int thread = -1);

protected:
    /// @brief 通知协程调度器有任务了
    virtual void tickle();

    /// @brief 协程调度函数
    void run();

    /// @brief 返回是否可以停止
    /// @return 
    virtual bool stopping();

    /// @brief 协程无任务可调度时执行的idle协程
    virtual void idle();

    /// @brief 设置当前的协程调度器
    void set_this();

    /// @brief 是否有空闲线程
    bool has_idle() { return idle_count > 0; }

private:
    /// @brief 协程调度启动
    /// @param fc 协程或者函数
    /// @param thread 协程数量
    template<class FiberOrCb>
    bool schedule_no_lock(FiberOrCb fc, int thread) {
        bool need_ticks = tasks.empty();
        FiberAndThread ft(fc, thread);
        if (ft.fiber)
        {   
            // 将协程设置为调度状态
            ft.fiber->in_sche();
            // 恢复协程的状态
            ft.fiber->set_state(FiberState::READY);
        }
        if (ft.fiber || ft.cb) 
        {
            tasks.push_back(std::move(ft));
        }
        return need_ticks;
    }

private:
    struct FiberAndThread
    {
        Fiber::ptr fiber;           // 协程
        std::function<void()> cb;   // 协程执行的函数
        int t_id;                   // 线程id

        FiberAndThread(Fiber::ptr f, int thr)
        : fiber(f), t_id(thr)
        {}

        FiberAndThread(std::function<void()> f, int thr)
        : cb(f), t_id(thr)
        {}

        FiberAndThread(std::function<void()> *c, int thr) 
        : t_id(thr)
        {
            cb.swap(*c);
        }

        FiberAndThread(Fiber::ptr *f, int thr)
        : t_id(thr)
        {
            fiber.swap(*f);
        }

        FiberAndThread()
        : t_id(-1)
        {}

        void reset() {
            fiber = nullptr;
            cb = nullptr;
            t_id = -1;
        }
    };

private:
    std::mutex mtx;                         // 维护任务队列的互斥锁
    std::vector<std::thread> threads;       // 线程池
    std::list<FiberAndThread> tasks;        // 任务队列
    Fiber::ptr call_fiber;                  // 调度协程
    std::string name;                       // 调度器名称

private:
    std::vector<pid_t> t_ids;                           // 线程id数组
    std::size_t t_count = 0;                            // 线程数量
    std::atomic<std::size_t> active_count = {0};        // 工作线程数量
    std::atomic<std::size_t> idle_count = {0};          // 空闲线程数量
    bool pause = true;                                  // 线程池是否停止
    int main_thread = -1;                               // 主线程id
};

}   // coroutine   
}   // DBServer

#endif // !COROUTINE_SCHEDULER_H